[userspace LL] vregion related syscalls - #11108
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Zephyr userspace support for SOF “vregion” allocations to enable userspace LL + DP integration (part of #10945), including syscall plumbing and module-adapter wiring to map vregion memory into the LL userspace memory domain.
Changes:
- Introduces Zephyr syscall handlers/marshalling for vregion alloc/free/get/put/set_interim.
- Refactors Zephyr vregion implementation entrypoints to
z_impl_*to back the new syscalls. - Extends module-adapter allocation flow to create/map/unmap vregions for DP modules and plumbs vregion start/size through
mod_alloc_ctx.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| zephyr/syscall/vregion.c | New syscall verification + marshalling includes for vregion APIs. |
| zephyr/lib/vregion.c | Switches vregion APIs to z_impl_* entrypoints and adjusts symbol exports accordingly. |
| zephyr/Kconfig | Adds SOF_USERSPACE_INTERFACE_VREGION and selects it from SOF_USERSPACE_LL. |
| zephyr/include/rtos/alloc.h | Extends mod_alloc_ctx with vregion start/size metadata for domain mapping. |
| zephyr/CMakeLists.txt | Adds syscall header generation and builds the new vregion syscall source. |
| src/include/sof/lib/vregion.h | Marks vregion APIs as __syscall and includes generated syscall header. |
| src/include/sof/audio/module_adapter/module/generic.h | Exposes module-adapter vregion map/unmap as syscalls for full Zephyr app. |
| src/audio/module_adapter/module_adapter.c | Implements vregion creation + mem-domain partition mapping and adds syscall verifiers. |
| src/audio/buffers/comp_buffer.c | Routes vregion-backed buffer free through the new shared vregion-free helper. |
Suppressed comments (2)
src/audio/module_adapter/module_adapter.c:134
- module_adapter_vreg_free() decrements the vregion refcount (and may free the vregion pages) before removing the user mem-domain partitions. If vregion_put() frees the pages, the user partition remains until module_adapter_vreg_unmap() runs, creating a window where freed (and potentially reallocated) pages stay user-accessible. Consider unmapping first and freeing the vregion atomically in kernel code when the refcount reaches 0.
void module_adapter_vreg_free(struct mod_alloc_ctx *alloc)
{
if (vregion_put(alloc->vreg))
return;
module_adapter_vreg_unmap(alloc);
sof_heap_free(alloc->heap, alloc);
src/audio/module_adapter/module_adapter.c:255
- The syscall verifier for module_adapter_vreg_unmap() only checks that the alloc struct is readable. In userspace-LL configurations alloc lives in user-writable memory, so a caller can forge vreg_start/vreg_size and attempt to remove arbitrary partitions from zephyr_ll_mem_domain(). Add validation that alloc refers to an expected allocation and that (vreg_start,vreg_size) match the vregion’s actual mem_info (or avoid taking alloc from user-space entirely).
void z_vrfy_module_adapter_vreg_unmap(const struct mod_alloc_ctx *alloc)
{
K_OOPS(K_SYSCALL_MEMORY_READ(alloc, sizeof(*alloc)));
z_impl_module_adapter_vreg_unmap(alloc);
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| memset(mod, 0, sizeof(*mod)); | ||
| alloc->heap = mod_heap; | ||
| alloc->vreg = mod_vreg; | ||
| alloc->vreg_start = vreg_start; | ||
| alloc->vreg_size = vreg_size; |
| struct k_mem_partition part = { | ||
| .start = *vreg_start, | ||
| .size = *vreg_size, | ||
| .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB, | ||
| }; | ||
| int ret = k_mem_domain_add_partition(zephyr_ll_mem_domain(), &part); | ||
|
|
||
| if (ret < 0) { | ||
| vregion_put(vr); | ||
| return NULL; | ||
| } | ||
|
|
||
| part.start = (uintptr_t)sys_cache_uncached_ptr_get((void *)part.start); | ||
| part.attr = K_MEM_PARTITION_P_RW_U_RW; | ||
|
|
||
| ret = k_mem_domain_add_partition(zephyr_ll_mem_domain(), &part); | ||
| if (ret < 0) { | ||
| vregion_put(vr); | ||
| return NULL; | ||
| } |
| static bool vregion_verify(struct vregion *vr) | ||
| { | ||
| if (!vr) | ||
| return false; | ||
|
|
||
| size_t vr_size = 0; | ||
| uintptr_t vr_start; | ||
|
|
||
| vregion_mem_info(vr, &vr_size, &vr_start); | ||
| if (vr_size) | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); | ||
|
|
||
| return true; |
| #include <stddef.h> | ||
| #include <stdint.h> | ||
| #include <zephyr/toolchain.h> | ||
|
|
| __syscall struct vregion *module_adapter_vreg_new(const struct comp_ipc_config *config, | ||
| uintptr_t *vreg_start, size_t *vreg_size); | ||
| __syscall void module_adapter_vreg_unmap(const struct mod_alloc_ctx *alloc); |
| zephyr_syscall_header(include/rtos/alloc.h) | ||
| zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_INTERFACE_ALLOC syscall/alloc.c) | ||
| zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/vregion.h) | ||
| zephyr_library_sources(syscall/vregion.c) |
4f46949 to
296ef8b
Compare
Add two syscall functions to allocate and map, and to unmap vregion for userspace modules. For now only used for DP modules. Add module_adapter.c to cmocka builds for the new module_adapter_vreg_free() function, which is now called in comp_buffer.c. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Make vregion_alloc(), vregion_alloc_coherent(), vregion_alloc_align(), vregion_alloc_coherent_align(), and vregion_free() available as Zephyr system calls for user-space threads. Add K_SYSCALL_MEMORY_WRITE verification to all syscall handlers to validate the calling thread has access to the vregion's managed memory area. Add CONFIG_SOF_USERSPACE_INTERFACE_VREGION Kconfig option to control the feature. It is auto-selected by SOF_USERSPACE_LL when SOF_VREGIONS is enabled. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extract common syscall verification code into a function. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
vregion_get(), vregion_put() and vregion_set_interim() should also be callable from the userspace. Make them syscalls. Also remove redundant symbol exporting since the vregion API shouldn't be used directly by LLEXT modules. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
kv2019i
left a comment
There was a problem hiding this comment.
Please check inline, concern with the syscall verify function.
| void z_vrfy_module_adapter_vreg_unmap(const struct mod_alloc_ctx *alloc) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_READ(alloc, sizeof(*alloc))); | ||
| z_impl_module_adapter_vreg_unmap(alloc); |
There was a problem hiding this comment.
Hmm, this is not safe, user-space can pass arbitrary alloc->vreg and this is passed unchecked to kernel code.
vregion system calls, needed when integrating userspace LL and DP
part of #10945